package org.easy.elasticsearch;


import lombok.Getter;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 通用方法封装工具类
 */
@Getter
public class CommonElasticsearchTemplate {

    public CommonElasticsearchTemplate(ElasticsearchRestTemplate elasticsearchRestTemplate) {
        this.elasticsearchRestTemplate = elasticsearchRestTemplate;
    }

    private final ElasticsearchRestTemplate elasticsearchRestTemplate;


    public <T extends BaseIndexEsDto> SearchHits<T> page(Query query, Class<T> clazz, String... indexNames) {
        return elasticsearchRestTemplate.search(query, clazz, IndexCoordinates.of(indexNames));
    }

    public <T extends BaseIndexEsDto> List<T> search(Query query, Class<T> clazz, String... indexNames) {
        SearchHits<T> search = elasticsearchRestTemplate.search(query, clazz, IndexCoordinates.of(indexNames));
        return search.stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    public <T extends BaseIndexEsDto> Boolean exists(Class<T> clazz) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(clazz);
        return indexOperations.exists();
    }

    public <T extends BaseIndexEsDto> Boolean exists(String... indexNames) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexNames));
        return indexOperations.exists();
    }


    public <T extends BaseIndexEsDto> void reCreateIndex(Class<T> clazz) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(clazz);
        indexOperations.delete();
        indexOperations.create();
    }

    public <T extends BaseIndexEsDto> void reCreateIndex(String... indexNames) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexNames));
        indexOperations.delete();
        indexOperations.create();
    }

    public <T extends BaseIndexEsDto> void insert(List<T> data) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(data.get(0).getClass());
        if (!indexOperations.exists()) {
            indexOperations.create();
            indexOperations.putMapping(indexOperations.createMapping(data.get(0).getClass()));
        }

        elasticsearchRestTemplate.save(data);
    }

    public <T extends BaseIndexEsDto> void insert(List<T> data, String... indexName) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexName));
        if (!indexOperations.exists()) {
            indexOperations.create();
            indexOperations.putMapping(indexOperations.createMapping(data.get(0).getClass()));
        }

        elasticsearchRestTemplate.save(data, IndexCoordinates.of(indexName));
    }

    public <T extends BaseIndexEsDto> void insert(T data) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(data.getClass());
        if (!indexOperations.exists()) {
            indexOperations.create();
            indexOperations.putMapping(indexOperations.createMapping(data.getClass()));
        }

        elasticsearchRestTemplate.save(data);
    }

    public <T extends BaseIndexEsDto> void insert(T data, String... indexName) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexName));
        if (!indexOperations.exists()) {
            indexOperations.create();
            indexOperations.putMapping(indexOperations.createMapping(data.getClass()));
        }

        elasticsearchRestTemplate.save(data, IndexCoordinates.of(indexName));
    }

    public <T extends BaseIndexEsDto> void deleteById(T t, String... indexName) {
        elasticsearchRestTemplate.delete(t, IndexCoordinates.of(indexName));
    }

    public <T extends BaseIndexEsDto> void updateAllById(T data, String... indexName) {
        elasticsearchRestTemplate.delete(data, IndexCoordinates.of(indexName));
        insert(data, indexName);
    }

    public <T extends BaseIndexEsDto> void deleteById(T t) {
        elasticsearchRestTemplate.delete(t);
    }

    public <T extends BaseIndexEsDto> void updateAllById(T data) {
        elasticsearchRestTemplate.delete(data);
        insert(data);
    }


    /**
     * 模糊搜索命中的前10个
     *
     * @param field 模糊搜索的字段
     * @param value 模糊搜索的值
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> fuzzySearch(String field, String value, Class<T> clazz) {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.fuzzyQuery(field, value))
                .withPageable(PageRequest.of(1, 10))
                .build();
        SearchHits<T> searchHits = elasticsearchRestTemplate.search(searchQuery, clazz);
        return searchHits.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

//    void searchCSaasReservationEs() {
//        String text = "1";
//        Long companyId = 60l;
//
//        BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery()
//                .should(QueryBuilders.matchQuery("reservationPatientName", text))
//                .should(QueryBuilders.matchQuery("reservationPatientPhone", text)
//                );
//        QueryBuilder mustQueryBuilder = QueryBuilders.boolQuery()
//                .filter(QueryBuilders.termQuery("userCompanyinfoId", companyId))
//                .filter(shouldQueryBuilder);
//        //构建高亮查询
//        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
//                .withQuery(mustQueryBuilder)
//                .withHighlightFields(new HighlightBuilder.Field("reservationPatientName"), new HighlightBuilder.Field("reservationPatientPhone"))
//                .withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>"))
//                .build();
//        //查询
//        SearchHits<SaasReservation> search = elasticsearchTemplate.search(searchQuery, SaasReservation.class);
//        //得到查询返回的内容
//        List<SearchHit<SaasReservation>> searchHits = search.getSearchHits();
//
//        //设置一个最后需要返回的实体类集合
//        List<SaasReservation> Companyinfos = new ArrayList<>();
//        //遍历返回的内容进行处理
//        for (SearchHit<SaasReservation> searchHit : searchHits) {
//            //高亮的内容
//            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
//            //System.out.println(highlightFields);
//            //将高亮的内容填充到content中
//            searchHit.getContent().setReservationPatientName(highlightFields.get("reservationPatientName") == null ? searchHit.getContent().getReservationPatientName() : highlightFields.get("reservationPatientName").get(0));
//            searchHit.getContent().setReservationPatientPhone(highlightFields.get("reservationPatientPhone") == null ? searchHit.getContent().getReservationPatientPhone() : highlightFields.get("reservationPatientPhone").get(0));
//
//            //放到实体类中
//            Companyinfos.add(searchHit.getContent());
//            System.out.println(searchHit.getContent());
//        }
//
//    }
//
//    void Test() {
//        QueryBuilder mustQueryBuilder = QueryBuilders.boolQuery()
//                .filter(QueryBuilders.termQuery("id", 178l));
//
//        //构建高亮查询
//        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
//                .withQuery(mustQueryBuilder).build();
//        //查询
//        SearchHits<SaasReservation> search = elasticsearchTemplate.search(searchQuery, SaasReservation.class);
//        //得到查询返回的内容
//        List<SearchHit<SaasReservation>> searchHits = search.getSearchHits();
//
//        //设置一个最后需要返回的实体类集合
//        List<SaasReservation> Companyinfos = new ArrayList<>();
//        //遍历返回的内容进行处理
//        for (SearchHit<SaasReservation> searchHit : searchHits) {
//            Companyinfos.add(searchHit.getContent());
//            System.out.println(searchHit.getContent());
//        }
//    }
//
//    public List<SysInternational> transform(Set<String> keys, Integer internationalType, String locale) {
//
//        QueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
//                .filter(QueryBuilders.termsQuery("key", keys))
//                .filter(QueryBuilders.termQuery("internationalType", internationalType))
//                .filter(QueryBuilders.termQuery("languageCode", locale));
//
//        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
//                .withQuery(boolQueryBuilder).build();
//
//        try {
//            if (InternationalType.CHINA_AREA_FULL_NAME.getType() == internationalType || InternationalType.CHINA_AREA_SIMPLE_NAME.getType() == internationalType) {
//                SearchHits<InternationalChinaAddressEsDto> search = elasticsearchTemplate.search(nativeSearchQuery, InternationalChinaAddressEsDto.class);
//                List<InternationalChinaAddressEsDto> collect = search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
//                return BeanCopierUtil.copyList(collect, SysInternational.class);
//            }
//
//            SearchHits<InternationalEsDto> search = elasticsearchTemplate.search(nativeSearchQuery, InternationalEsDto.class);
//            List<InternationalEsDto> collect = search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
//            return BeanCopierUtil.copyList(collect, SysInternational.class);
//
//        } catch (Exception e) {
//            log.error(e.getMessage());
//            return sysInternationalMapper.transform(keys, internationalType, locale);
//        }
//    }
}